const config = require('../config/dbConfig');
const logger = require('log4js').getLogger();
const mysql = require('mysql');
const pool = mysql.createPool(config);


class DBUtil {

    constructor() {
        pool.getConnection((err, connection) => {
            if (err || !connection) {
                logger.error("Database init error !!!", err);
                throw new Error("Database init error !!!");
            }
            logger.info(">>>> Database init over. <<<<");
            connection.release();
        });
    }


    query(sql, params) {
        let promise = new Promise(function (resolve, reject) {

            let format_sql = mysql.format(sql, params);
            logger.debug("-->sql query : %s ", format_sql);

            pool.query(format_sql, function (err, rows) {
                if (err) {
                    reject(err);
                }

                resolve(rows);
            });
        });
        return promise;
    }

    queryForInt(sql, params) {
        return this.query(sql, params).then(function (rows) {
            let promise = new Promise(function (resolve, reject) {
                let keys = Object.keys(rows[0]);
                if (keys.length != 1) {
                    reject(new Error('DB queryForInt must be have only one field!'));
                }

                resolve(rows[0][keys[0]]);
            });
            return promise;
        });
    }

    insert(sql, params) {
        let promise = new Promise(function (resolve, reject) {
            let format_sql = mysql.format(sql, params);
            logger.debug('-->sql insert ,sql : %s', format_sql);
            pool.query(format_sql, (err, results, fields) => {
                if (err) {
                    reject(err);
                }

                resolve(results ? (results.insertId || 0) : 0);
            });
        });
        return promise;
    }

    update(sql, params, _delete) {
        let promise = new Promise(function (resolve, reject) {
            let format_sql = mysql.format(sql, params);
            logger.debug("-->sql update : %s ", format_sql);
            pool.query(format_sql, (err, results, fields) => {
                if (err) {
                    reject(err);
                }

                if (_delete) {
                    resolve(results ? (results.affectedRows || 0) : 0);
                } else {
                    resolve(results ? (results.changedRows || 0) : 0);
                }
            });
        });

        return promise;
    }


    delete(sql, params) {
        return this.update(sql, params, true).then(function (affected) {
            return new Promise(function (resolve, reject) {
                resolve(affected);
            });
        });
    }

    getConnection(cb) {
        return pool.getConnection(cb);
    }

    beginTransaction() {
        let promise = new Promise(function (resolve, reject) {
            pool.getConnection((err, connection) => {
                if (err) {
                    reject(err);
                }

                connection.beginTransaction(err => {
                    if (err) {
                        reject(err);
                    }
                    resolve(connection);
                });

            });
        });

        return promise;
    }

    commit(connection) {

        let promise = new Promise(function (resolve, reject) {
            connection.commit(function (err) {
                if (err) {
                    return connection.rollback(function () {
                        connection.release();
                        reject(reject);
                    });
                }
                connection.release();
                resolve();
            });
        });
        return promise;
    }

    rollback(connection) {
        connection.rollback(function () {
            connection.release();
        });
    }
}

module.exports = new DBUtil();
